package ldh.serialize.type;

import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import ldh.serialize.BinarySerialized;
import ldh.serialize.Serialized;
import ldh.serialize.io.ByteBuf;
import ldh.serialize.util.SerializedUtil;
import ldh.serialize.util.TransferUtil;

public class MapSerialized<M extends Map<K, T>, K extends Serializable, T extends Serializable> implements BinarySerialized<M> {

	public Serialized<T> valueSerialized;
	public Serialized<K> keySerialized;
	
	public MapSerialized(Serialized<K> keySerialized, Serialized<T> valueSerialized) {
		this.keySerialized = keySerialized;
		this.valueSerialized = valueSerialized;
	}

	
	@Override
	public void write(ByteBuf out, M m) throws IOException {
		if (m == null) {
			SerializedUtil.writeByte(out, (byte)0);
			return;
		}
		if (!(keySerialized instanceof BinarySerialized) || !(valueSerialized instanceof BinarySerialized)) {
			throw new RuntimeException("serialized is not BinarySerialized");
		}
		BinarySerialized<K> ks = (BinarySerialized<K>) this.keySerialized;
		BinarySerialized<T> vs = (BinarySerialized<T>) this.valueSerialized;
		
		SerializedUtil.writeByte(out, (byte)1);
		try {
			Map<K, T> map = (Map<K, T>)m;
			out.writeBytes(TransferUtil.intToBytes(map.size()));
			for (Entry<K, T> entry : map.entrySet()) {
				ks.write(out, entry.getKey());
				vs.write(out, entry.getValue());
			}
		} catch (IOException e) {
			e.printStackTrace();
		} 
	}

	@Override
	public M read(ByteBuf in) throws IOException {
		if (!(keySerialized instanceof BinarySerialized) || !(valueSerialized instanceof BinarySerialized)) {
			throw new RuntimeException("serialized is not BinarySerialized");
		}
		BinarySerialized<K> ks = (BinarySerialized<K>) this.keySerialized;
		BinarySerialized<T> vs = (BinarySerialized<T>) this.valueSerialized;
		
		Integer size = SerializedUtil.readInteger(in);
		if (size == null) {
			return null;
		}
		Map<K, T> map = new HashMap<K, T>();
		for (int i=0; i<size; i++) {
			K k = ks.read(in);
			T t = vs.read(in);
			
			map.put(k, t);
		}
		return (M) map;
	}

	@Override
	public Class<M> getClassType() {
		return null;
	}
}
